%%%-------------------------------------------------------------------
%%% File    : p40.erl
%%% Author  : Plamen Dragozov <plamen at dragozov.com>
%%% Description : 
%%% An irrational decimal fraction is created by concatenating the 
%%% positive integers:
%%%
%%% 0.123456789101112131415161718192021...
%%%
%%% It can be seen that the 12^(th) digit of the fractional part is 1.
%%%
%%% If d_(n) represents the n^(th) digit of the fractional part, find 
%%% the value of the following expression.
%%%
%%% d_(1) *d_(10) * d_(100) * d_(1000) * d_(10000) * d_(100000) * d_(1000000
%%% Created : 29 Dec 2008
%%%-------------------------------------------------------------------
-module(p40).

%% API
-compile(export_all).

%%====================================================================
%% API
%%====================================================================
%%--------------------------------------------------------------------
%% Function: solution() -> N
%% Description: Calculate the expression as defined in the problem,
%%--------------------------------------------------------------------
solution()->
    which_digit(1) 
        *which_digit(10)
        *which_digit(100)
        *which_digit(1000)
        *which_digit(10000)
        *which_digit(100000)
        *which_digit(1000000).

%%====================================================================
%% Internal functions
%%====================================================================
%Find the digit at position N in the sequence 123456789101112...
%1. Find which number's digits take that position
%2. Find which digit in that number is at that position
%3. Parse the digit
which_digit(N) ->
    {Floor, Pow10} = floor_pow10(N),
    %Floor is the first with the same number of digits as N
    %Rest is the difference between Floor and N
    Rest = N - Floor - 1,%0 based
    Digits = Pow10 + 1,%how many digits in the numbers betwen Floor and N
    NumberIndex = Rest div Digits,
    DigitIndex = Rest rem Digits,%which digit
    Number = trunc(math:pow(10, Pow10)) + NumberIndex,%which number
    get_digit(Number, DigitIndex).

%Get the digit at index Index in the integer Number
get_digit(Number, Index) ->
    Digits = array:from_list(digits(Number, [])),
    array:get(Index, Digits).

%convert a number to a list of digits
digits(0, Acc) ->
    Acc;
digits(Number, Acc) ->
    digits(Number div 10, [Number rem 10 | Acc]).

%find the smalles number of the power of 10 range where N belongs.
% Example 0-9 belong to the 10^0 range and 0 is the floor_pow10 for them
% 1000 - 9999 belong to the 10^3 range and 1000 is the floor_pow10
floor_pow10(N) ->
    floor_pow10(N, 0, 0).
floor_pow10(N, Pow10, Floor) ->
    NewFloor = Floor + trunc((Pow10 + 1)*9*math:pow(10, Pow10)),
    case NewFloor > N of
        true ->
            {Floor, Pow10};
        _ -> floor_pow10(N, Pow10+1, NewFloor)
    end.

